/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
 */

package com.jinhe.tss.cms.service.impl;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.jinhe.tss.cms.CMSConstants;
import com.jinhe.tss.cms.dao.IArticleDao;
import com.jinhe.tss.cms.dao.IChannelDao;
import com.jinhe.tss.cms.entity.Article;
import com.jinhe.tss.cms.entity.ArticleLation;
import com.jinhe.tss.cms.entity.ArticleLationId;
import com.jinhe.tss.cms.entity.Attachment;
import com.jinhe.tss.cms.entity.AttachmentId;
import com.jinhe.tss.cms.entity.Channel;
import com.jinhe.tss.cms.entity.ChannelArticle;
import com.jinhe.tss.cms.entity.ChannelArticleId;
import com.jinhe.tss.cms.entity.WordsFilter;
import com.jinhe.tss.cms.helper.ArticleHelper;
import com.jinhe.tss.cms.helper.ArticleQueryCondition;
import com.jinhe.tss.cms.publish.PublishManger;
import com.jinhe.tss.cms.service.IArticleService;
import com.jinhe.tss.component.param.extend.ParamConfig;
import com.jinhe.tss.component.support.persistence.pagequery.PageInfo;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.sso.Environment;
import com.jinhe.tss.core.util.BeanUtil;
import com.jinhe.tss.core.util.EasyUtils;
import com.jinhe.tss.core.util.FileHelper;
 
public class ArticleService implements IArticleService {
    
    protected final Logger log = Logger.getLogger(getClass());

	@Autowired private IArticleDao articleDao;
	@Autowired private IChannelDao channelDao;
 
    public Article getArticleById(Long articleId) {
        Article article = getArticleOnly(articleId);
        article.getAttachments().putAll(articleDao.getArticleAttachments(articleId));;
        return article;
    }
 
	public void copyArticle(Long articleId, Long channelId, boolean copyTo) {
		Article article = getArticleOnly(articleId);
		
		Article newarticle = new Article();
		BeanUtil.copy(newarticle, article, Article.IGNORE_PROPERTIES);
		newarticle.setScoreCount(null);
		newarticle.setScores(null);
		newarticle.setStatus(CMSConstants.START_STATUS);
		newarticle.setHitCount(CMSConstants.DEFAULT_HIT_COUNT);
		if ( !copyTo )
			newarticle.setTitle(CMSConstants.COPY_NAME_PREFIX + article.getTitle());
		
		newarticle.setWzrq(new Date());
		newarticle.getDynpropertiesMap().putAll(article.getDynpropertiesMap());
		articleDao.saveArticle(newarticle);
        
		// 新增栏目文章关系
        createChannelArticleRelation(channelId, newarticle.getId());
        
		// 分发源的相关信息
		List<?> list = channelDao.getChannelTreeUpNoPermission(channelId);
		String sourcePath = "";
		for (int i = 0; i < list.size(); i++) {
			Channel temp = (Channel) list.get(i);
			sourcePath += "/" + temp.getName();
		}
            
        Channel site = channelDao.getSiteByChannel(channelId);
        Object[] objects = new Object[4];
		objects[0] = site.getId();
		objects[1] = channelId;
		objects[2] = newarticle.getId();
		objects[3] = site.getName() + sourcePath;
		
		// 维护相关栏目的栏目文章关系
		addChannelAndArticleRelationShip(channelId, newarticle.getId(), objects);
		
		// 复制附件信息
		Map<String, Attachment> attachmentMap = articleDao.getArticleAttachments(articleId);
		for ( Attachment attachment : attachmentMap.values() ) {
			// 只是针对附件在服务器上的文章进行处理，导入文章的附件不在以下代码的处理范围
            String path = site.getAttanchmentPath(attachment);
            File file = new File(site.getPath() + "/" + path + "/" + attachment.getLocalPath());
            String localPath = addFile2Path(file, ArticleHelper.getAttachmentPath(site, attachment.getType()));

			// 新增附件信息
			Attachment attach = new Attachment(); // 新增附件信息
			BeanUtil.copy(attach, attachment);
			attach.setId(attachment.getId());
			attach.getId().setArticleId(newarticle.getId());
            
			String year = new SimpleDateFormat("yyyy").format(new Date()); // 取到年度
			attach.setLocalPath(localPath.substring(localPath.indexOf(year)));
			attach.setUploadDate(new Date());
			articleDao.createObject(attach);
		}
	}

    /**
     * 新增附件
     */
    private String addFile2Path(File file, String path) {
        File dir = new File(path);
        
        // 如果是在统一目录下，则不用再复制。
        if(file.getParentFile().equals(dir)) return file.getPath();
        
        if (!dir.exists()) dir.mkdirs();
        
        String filaName = FileHelper.copyFile(dir, file, true, false);
        return path + "/" + filaName;
    }
    
	public void createArticle(Article article, Long channelId, String attachList, Long tempArticleId) {
		Channel channel = channelDao.getEntity(channelId);
 
		Date calculateOverDate = ArticleHelper.calculateOverDate(article, channel);
        if( calculateOverDate != null ) {
			article.setOverdueDate(calculateOverDate);
        }
		articleDao.saveArticle(article);
        
		// 处理附件
        List<String> attachSeqNos = new LinkedList<String>();
		if ( !EasyUtils.isNullOrEmpty(attachList) ) {			
            StringTokenizer st = new StringTokenizer(attachList, ",");
            while (st.hasMoreTokens()) {
                attachSeqNos.add(st.nextToken());
            }
        }
		
        Map<String, Attachment> attachments = articleDao.getArticleAttachments(tempArticleId); // 后台查找的新建文章时上传的附件列表
        for ( Attachment attachment : attachments.values() ) {
			Integer seqNo = attachment.getId().getSeqNo();
            if (attachSeqNos.contains(seqNo.toString())) { // 判断附件在文章保存时是否还存在
				translatePath(attachment, article, channelId);
				
				// 新增附件信息
				Attachment attach = new Attachment();
				BeanUtil.copy(attach, attachment);
				attach.setId(new AttachmentId(article.getId(), seqNo));
				articleDao.createObject(attach);
			}
            else {
				// 删除附件
				String[] uploadName = ArticleHelper.getAttachUploadPath(channelDao.getSiteByChannel(channelId), attachment);
                new File(uploadName[0]).delete();
			}
            //删除老的附件信息
			articleDao.delete(attachment);
		}
		// 更新文章内容中资源的连接地址
		articleDao.saveArticle(article);

		// 将栏目文章关系中文章临时ID对应栏目关系删除
        articleDao.deleteAll(articleDao.getEntities("from ChannelArticle ca where ca.id.articleId > 100000000"));
        createChannelArticleRelation(channelId, article.getId());

		// 分发源的相关信息
		Channel site = channelDao.getEntity(channel.getSiteId());
		List<?> list = channelDao.getChannelTreeUpNoPermission(channel.getId());
		String sourcePath = "";
		if ( list != null) {
			for (int i = 0; i < list.size(); i++) {
				Channel temp = (Channel) list.get(i);
				sourcePath += "/" + temp.getName();
			}
		}
        Object[] objects = new Object[4];
		objects[0] = site.getId();
		objects[1] = channel.getId();
		objects[2] = article.getId();
		objects[3] = site.getName() + sourcePath;

		// 维护相关栏目的栏目文章关系
		addChannelAndArticleRelationShip(channelId, article.getId(), objects);
	}
    
    public void createChannelArticleRelation(Long channelId, Long articleId) {
        // 栏目文章关系
        ChannelArticle ca = new ChannelArticle();
        ca.setId(new ChannelArticleId(channelId, articleId));
        ca.setSeqNo(articleDao.getChannelArticleNextOrder(channelId));
        articleDao.createObject(ca);
    }

    /**
     * 新增文章时，给“分发至”的栏目进行栏目文章关系表的维护
     */
    private void addChannelAndArticleRelationShip(Long channelId, Long articleId, Object[] objects) {
        List<?> desList = channelDao.getChannelDestinationByChannelId(channelId);
        for (int i = 0; i < desList.size(); i++) {
            Long desChannelId = ((Channel) desList.get(i)).getId();
            ChannelArticle channelArticle = new ChannelArticle();
            channelArticle.setId(new ChannelArticleId(desChannelId, articleId));
            
            channelArticle.setSourceSiteId((Long) objects[0]);
            channelArticle.setSourceChannelId((Long) objects[1]);
            channelArticle.setSourceArticleId((Long) objects[2]);
            channelArticle.setPathName((String) objects[3]);
            
            channelArticle.setIsTop(CMSConstants.FALSE);
            channelArticle.setSeqNo(articleDao.getChannelArticleNextOrder(desChannelId));
            channelArticle.setArticleOrigin(CMSConstants.ARTICLE_DISTRIBUTE);
            articleDao.createObject(channelArticle);
        }
    }

	/**
	 * 将文章内容中的临时地址替换成真实地址。
     * 主要是将临时生成的附件ID替换成附件所属文章的ID。
	 */
	private void translatePath(Attachment attachment, Article article, Long channelId) {
		String attRelationDownloadUrl = attachment.getRelationDownloadUrl(); // download.fun?id=1216&seqNo=1
        attRelationDownloadUrl = attRelationDownloadUrl.replaceAll("&", "&amp;"); //将&替换成&amp;
        
		StringBuffer sb = new StringBuffer(article.getContent());
		int index = sb.indexOf(attRelationDownloadUrl);
		while (index != -1) {
			StringBuffer buffer = new StringBuffer();
			int idIndex = attRelationDownloadUrl.indexOf("?id=");
			String realAttUploadName;
			if (idIndex != -1) {
				realAttUploadName = attRelationDownloadUrl.substring(0, idIndex + 4);
				realAttUploadName += article.getId() + attRelationDownloadUrl.substring(attRelationDownloadUrl.indexOf("&amp;"));
				buffer.append(sb.substring(0, index)).append(realAttUploadName).append(sb.substring(index + attRelationDownloadUrl.length()));
				sb = buffer;
			}
			index = sb.indexOf(attRelationDownloadUrl);
		}
		article.setContent(sb.toString());
	}
    
    public void updateArticle(Article article, Long channelId, String attachList) {
    	
        articleDao.saveArticle(article);
        
        // 处理附件, attachList为需要删除的附件列表
        if ( !EasyUtils.isNullOrEmpty(attachList) ) {
            StringTokenizer st = new StringTokenizer(attachList, ",");
            List<String> attachSeqNos = new LinkedList<String>();
            while (st.hasMoreTokens()) {
                attachSeqNos.add(st.nextToken());
            }
            
            Map<String, Attachment> attachments = articleDao.getArticleAttachments(article.getId());
            for ( Attachment attachment : attachments.values() ) {
                if (!attachSeqNos.contains(attachment.getId().getSeqNo().toString()))
                   continue;
                
                // 删除附件
                articleDao.delete(attachment);
                Channel site = channelDao.getSiteByChannel(channelId);
                String path = site.getPath() + "/" + site.getAttanchmentPath(attachment) + "/" + attachment.getLocalPath();
                new File(path).delete();
            }
        }
    }

    public void deleteArticle(Long articleId, Long channelId) {
        ChannelArticleId id = new ChannelArticleId(channelId, articleId);
        ChannelArticle ca = (ChannelArticle) articleDao.getEntity(ChannelArticle.class, id);
        
		if (CMSConstants.ARTICLE_DISTRIBUTE.equals(ca.getArticleOrigin())) { // 分发文章时应该只删除关系表信息
			articleDao.delete(getChannelArticle(articleId, channelId));
		} 
		else { 
			Article article = getArticleOnly(articleId);
            article.setChannelId(channelId);
            
            article.setSite(channelDao.getSiteByChannel(channelId));
            articleDao.deleteArticle(article);
		}
	}
    
    private Article getArticleOnly(Long articleId){
    	if (articleId == null)
            throw new BusinessException("参数articleId为空！");
    	
        Article article = (Article) articleDao.getEntity(Article.class, articleId);
        if (article == null) 
            throw new NullPointerException("未找到文章！");
        if (CMSConstants.TRUE.equals(article.getDeleted()))
            throw new BusinessException("文章已被删除至回收站中");
        
        return article;
    }
 
    public void moveArticle(Long articleId, Long oldChannelId, Long channelId) {
		// 移动前的栏目文章关系表信息
        ChannelArticleId id = new ChannelArticleId(oldChannelId, articleId);
		ChannelArticle exsitChannelArticle = (ChannelArticle) articleDao.getEntity(ChannelArticle.class, id);
		Integer articleOrigin  = exsitChannelArticle.getArticleOrigin();
		Integer isTop = exsitChannelArticle.getIsTop();
		
        // 删除原来普通文章的栏目文章关系信息
        articleDao.delete(exsitChannelArticle);
		
		// 新分发源信息：即目标栏目替代源栏目做为新的分发源
		Channel channel = channelDao.getEntity(channelId);
		Channel site =  channelDao.getEntity(channel.getSiteId());
		Long sourceSiteId = site.getId();
		String pathName = site.getName() + "/" + channel.getName();
		
		if ( CMSConstants.ARTICLE_COMMON.equals(articleOrigin) ) { // 移动的是普通文章
		    // 文章和目标栏目是否已经存在关系，如已存在则先删除
			ChannelArticle oldChannelArticle = articleDao.getChannelArticle(articleId, channelId);
			if (oldChannelArticle != null) {
				articleDao.delete(oldChannelArticle);
			}
				
			// 为移动的文章新增栏目文章关系信息
			ChannelArticle ca = new ChannelArticle();
			ca.setId(new ChannelArticleId(channelId, articleId));
			ca.setArticleOrigin(CMSConstants.ARTICLE_COMMON);
			ca.setIsTop(isTop);
			ca.setSeqNo(articleDao.getChannelArticleNextOrder(channelId));
			articleDao.createObject(ca);
			
			// 修改分发文章的栏目文章关系
	        List<?> existList = articleDao.getFFChannelArticleListByArticle(articleId);
	        updateExsitRelation(existList, sourceSiteId, channelId, pathName);
	        
			// 修改转载文章的栏目文章关系
			existList = articleDao.getZZChannelArticleList(articleId, oldChannelId);
			updateExsitRelation(existList, sourceSiteId, channelId, pathName);
		}
	}
    
    private void updateExsitRelation(List<?> existList, Long sourceSiteId, Long channelId, String pathName) {
    	// 修改文章和目标栏目之外的栏目直接的分发(或转载)关系，把分发源有移动前的栏目改为目标栏目
        for ( Object temp : existList ) {
            ChannelArticle channelArticle = (ChannelArticle) temp;
            channelArticle.setSourceSiteId(sourceSiteId);
            channelArticle.setSourceChannelId(channelId);
            channelArticle.setPathName(pathName);
            articleDao.updateWithoutFlush(channelArticle);
        }
    }

    public void moveArticleDownOrUp(Long articleId, Long toArticleId, Long channelId) {
		ChannelArticle ca1 = getChannelArticle(articleId, channelId);
		ChannelArticle ca2 = getChannelArticle(toArticleId, channelId);

		ca1.setSeqNo(ca2.getSeqNo());
		ca2.setSeqNo(ca1.getSeqNo());

		articleDao.update(ca1);
		articleDao.update(ca2);
	}

    public void moveArticleDownOrUpCross(Long articleId, Long channelId, Integer page, int direction){
		Long toArticleId = null;
		if (direction == 1) { // 下移
			PageInfo pageInfo = articleDao.getPageList(channelId, page + 1);
			Object[] nextPageFirst = (Object[]) pageInfo.getItems().get(0);
			toArticleId = (Long) nextPageFirst[0];
		} 
		else if (direction == -1) { // 上移
            PageInfo pageInfo = articleDao.getPageList(channelId, page - 1);
			Object[] prePageLast = (Object[]) pageInfo.getItems().get(pageInfo.getPageSize() - 1);
			toArticleId = (Long) prePageLast[0];
		}
        moveArticleDownOrUp(articleId, toArticleId, channelId);
	}

    public void lockingArticle(Long articleId) {
		Article article = (Article) getArticleOnly(articleId);
		if (CMSConstants.LOCKING_STATUS.equals(article.getStatus()))  {
			throw new BusinessException("文章已被锁定");
		}
        if (!CMSConstants.START_STATUS.equals(article.getStatus())) {
			throw new BusinessException("文章不处于初始状态，不能锁定");
        }
		
		article.setStatus(CMSConstants.LOCKING_STATUS);
		articleDao.update(article);
	}

	public void unLockingArticle(Long articleId) {
        Article article = (Article) getArticleOnly(articleId);
		if (CMSConstants.START_STATUS.equals(article.getStatus())) {
			throw new BusinessException("文章已被解除锁定");
		}
		if (!CMSConstants.LOCKING_STATUS.equals(article.getStatus())) {
			throw new BusinessException("文章不处于锁定状态，不能解除锁定");
		}
		
		article.setStatus(CMSConstants.START_STATUS);
		articleDao.update(article);
	}

    public void changeArticleStatus(Long articleId, Integer oldStatus, Integer status, Integer workflowId) {
        Article article = getArticleOnly(articleId);
		Integer articleStatus = article.getStatus();
		
		// 如果文章是XMLSTATUS状态时，等同于TOPUBLISH_STATUS状态(数据库状态为XMLSTATUS，当前状态为TOPUBLISH_STATUS不报错)
		if (!oldStatus.equals(articleStatus)) {
			if ( !CMSConstants.XML_STATUS.equals(articleStatus) && !CMSConstants.TOPUBLISH_STATUS.equals(oldStatus)) {
				throw new BusinessException("文章状态不同步，请刷新文章列表重新获取最新文章状态！");
			}
		}
		
		// publishFlag用来判断流程走到发布时是否要生成xml文件
		String publishFlag = ParamConfig.getAttribute(CMSConstants.PARAM_NAME_PUBLISHFLAG); 
		if (CMSConstants.BOOLEAN_TRUE.equals(publishFlag)) {
            // 流程回退到过期前，流程状态要保证在-1的状态；旧流程状态为 5：“已过期”
            if ( CMSConstants.TOPUBLISH_STATUS < oldStatus && CMSConstants.TOPUBLISH_STATUS.equals(status) ) { 
                status = CMSConstants.XML_STATUS;
            }
		}

		if (status.equals(article.getStatus())) {
			return; // 流程状态已经被改变（可能有其他人再同样操作）。
		}
		article.setStatus(status);
        
		Long channelId = articleDao.getChannelIdByArticleId(articleId);
		if (channelId == null) {
			throw new BusinessException("分发文章不能进行流程的修改！");
		}
		
		if (CMSConstants.BOOLEAN_TRUE.equals(publishFlag)) {// 流程走到发布时就要生成xml文件
			if ( CMSConstants.TOPUBLISH_STATUS > oldStatus && CMSConstants.TOPUBLISH_STATUS.equals(status) ) {
                publishArticle(article, channelId);
			}
            
            // 从已过期 和 待发布 状态回退时需要处理发布时间问题
            // 旧流程状态为 “待发布” 或 “已过期”
			// 新流程状态为 “待发布” 之前（已审核 或 已编辑） 且 不为 已发布 
            // 例如：已过期 回退至 已编辑， 将发布日期修改为空
			if (CMSConstants.TOPUBLISH_STATUS <= oldStatus && CMSConstants.TOPUBLISH_STATUS > status && !CMSConstants.XML_STATUS.equals(status)) {
				if (article.getIssueDate() != null && article.getIssueDate().before(new Date())) {
					article.setIssueDate(null);
				}
			}
		} 
		else if (CMSConstants.BOOLEAN_FALSE.equals(publishFlag)) { // 流程走到发布状态仅仅只是状态的改变，需要增量发布才能生成xml文件
			// 从已过期和xml文件状态回退时需要处理发布时间问题， 例如：已过期 回退至 已编辑， 将发布日期修改为空
			if ((CMSConstants.TOPUBLISH_STATUS < oldStatus   
                    || CMSConstants.XML_STATUS.intValue() == oldStatus.intValue()) // 旧流程状态oldStatus为 “已过期” 或 “已发布”
					&& CMSConstants.TOPUBLISH_STATUS >= status) { // 新流程状态为 “待发布” 之前（已审核 或 已编辑）
				if (article.getIssueDate() != null && !article.getIssueDate().after(new Date())) {
					article.setIssueDate(null);
				}
			}
		}
		articleDao.update(article);
	}
    
    private void publishArticle(Article article, Long channelId) {
        // 获取文章附件
        article.getAttachments().putAll(articleDao.getArticleAttachments(article.getId())); 
        article.setStatus(CMSConstants.XML_STATUS);
        
        // 发布时，如果文章设定的发布时间早于当前时间则更新发布时间。
        if (article.getIssueDate() == null || article.getIssueDate().before(new Date())) {
            article.setIssueDate(new Date());
        }
        Channel channel = channelDao.getEntity(channelId);
        article.setChannelId(channelId);
        article.setChannelName(channel.getName());
        article.setArticleTypeId(channel.getArticleTypeId());
        article.setTypeName(channel.getArticleTypeName());
        
        Channel site = channelDao.getEntity(channel.getSiteId());
        String publishPath = site.getPath() + "/" + ArticleHelper.getArticlePublishRule(article.getCreateTime());
        WordsFilter wordsFilter = (WordsFilter)articleDao.getEntity( WordsFilter.class, site.getId());
        
        String pubUrl = PublishManger.publishOneArticle(article, publishPath, wordsFilter);
        article.setPubUrl(pubUrl);
    }
 
	public void reshipArticle(Long articleId, Long channelId, Long fromChannelId){
		Article article = getArticleOnly(articleId);

		Article newArticle = new Article();
		BeanUtil.copy(newArticle, article, Article.IGNORE_PROPERTIES);
		newArticle.setStatus(CMSConstants.START_STATUS);
		newArticle.setHitCount(CMSConstants.DEFAULT_HIT_COUNT);
		newArticle.setDeleted(CMSConstants.FALSE);
		newArticle.setTitle(article.getTitle());
		newArticle.setArticleOrigin(CMSConstants.ARTICLE_RESHIP);
        newArticle.setWzrq(new Date());
		articleDao.create(newArticle);
        
		// 转载源关系信息
		Channel fromChannel = channelDao.getEntity(fromChannelId);
		Channel fromSite    = channelDao.getEntity(fromChannel.getSiteId());

		// 分发源关系信息
		Channel toChannel = channelDao.getEntity(channelId);
		Channel toSite    = channelDao.getEntity(toChannel.getSiteId());
		List<?> list = channelDao.getChannelTreeUpNoPermission(channelId);
		String oldSourcePath = "";
		for (int i = 0; i < list.size(); i++) {
			Channel channel = (Channel) list.get(i);
			oldSourcePath += "/" + channel.getName();
		}

		list = channelDao.getChannelTreeUpNoPermission(toChannel.getId());
		String newSourcePath = "";
		for (int i = 0; i < list.size(); i++) {
			Channel channel = (Channel) list.get(i);
			newSourcePath += "/" + channel.getName();
		}
        
        Object[] distributeInfos = new Object[4];
		distributeInfos[0] = toSite.getId();
		distributeInfos[1] = toChannel.getId();
		distributeInfos[2] = newArticle.getId();
		distributeInfos[3] = toSite.getName() + newSourcePath;

		// 新增栏目文章关系
		ChannelArticle ca = new ChannelArticle();
        ca.setId(new ChannelArticleId(channelId, newArticle.getId()));
		ca.setSourceSiteId(fromSite.getId());
		ca.setSourceChannelId(fromChannel.getId());
		ca.setSourceArticleId(article.getId());
		ca.setPathName(fromSite.getName() + oldSourcePath);
		ca.setIsTop(CMSConstants.FALSE);
		ca.setSeqNo(articleDao.getChannelArticleNextOrder(channelId));
		ca.setArticleOrigin(CMSConstants.ARTICLE_RESHIP);
		articleDao.createObject(ca);
		
		// 维护相关栏目的栏目文章关系
		addChannelAndArticleRelationShip(channelId, newArticle.getId(), distributeInfos);
	}
 
	public void doTopArticle(Long articleId, Long channelId) {
		ChannelArticle ca = getChannelArticle(articleId, channelId);		
		ca.setIsTop(CMSConstants.TRUE);
		articleDao.update(ca);
	}
 
	public void undoTopArticle(Long articleId, Long channelId) {
        ChannelArticle ca = getChannelArticle(articleId, channelId);
        ca.setIsTop(CMSConstants.FALSE);
        articleDao.update(ca);
	}

	public Object[] getArticleExistRelationship(Long articleId) {
        Object[] returnObjs = new Object[2];
		returnObjs[0] = channelDao.getAllSiteChannelList();
		returnObjs[1] = articleDao.getArticleLationsById(articleId);
		return returnObjs;
	}
 
	public void relatedArticleTo(Long articleId, String relatedArticleIds) {
	    // 先清除所有已经存在的关系信息
        articleDao.deleteAll(articleDao.getLationsById(articleId));
        
		if ( EasyUtils.isNullOrEmpty(relatedArticleIds)) {
			return;
		}
		
		String[] ids = relatedArticleIds.split(",");
		for (String id : ids) {
			ArticleLationId lationId = new ArticleLationId();
			lationId.setArticleId(articleId);
			lationId.setLationArticleId(new Long(id));
			
			ArticleLation lation = new ArticleLation();
			lation.setId(lationId);
			lation.setSeqNo(articleDao.getArticleLationNextOrder(articleId));
			articleDao.createObject(lation);
		}
	}
 
	public Object[] getDistributeArticleRelationShip(Long articleId, Long channelId) {
		List<Long> channelIdsCanAddArticle = channelDao.getSiteChannelIDsByOperationId(CMSConstants.OPERATION_ADD_ARTICLE);
        
        Object[] objects = new Object[3];
		objects[0] = channelDao.getAllSiteChannelList();
		objects[1] = EasyUtils.list2Str(channelIdsCanAddArticle);
		objects[2] = articleDao.getDispathedToChannels(articleId);
		return objects;
	}
 
	public void saveDistributeArticleRelationShip(Long articleId, Long channelId, String distributeToChannelIds) {
		articleDao.deleteAll(articleDao.getFFChannelArticleListByArticle(articleId));

		if ( EasyUtils.isNullOrEmpty(distributeToChannelIds)) {
			return;
		}
	
		String[] ids = distributeToChannelIds.split(",");
		for (int j = 0; j < ids.length; j++) {
			Long tempChannelId = new Long(ids[j]);
			ChannelArticle channelArticle = new ChannelArticle();
            channelArticle.setId(new ChannelArticleId(tempChannelId, articleId));
            channelArticle.setSeqNo(articleDao.getChannelArticleNextOrder(tempChannelId));
            channelArticle.setArticleOrigin(CMSConstants.ARTICLE_DISTRIBUTE);
            
			// 分发源的相关信息
			Channel rootChannel = channelDao.getEntity(channelId);
			Channel site =  channelDao.getEntity(rootChannel.getSiteId());
			List<?> list = channelDao.getChannelTreeUpNoPermission(channelId);
			String sourcePath = "";
			for (int i = 0; i < list.size(); i++) {
				Channel channel = (Channel) list.get(i);
				sourcePath += "/" + channel.getName();
			}
			channelArticle.setSourceSiteId(site.getId());
			channelArticle.setSourceChannelId(channelId);
			channelArticle.setSourceArticleId(articleId);
			channelArticle.setPathName(site.getName() + sourcePath);
			
			articleDao.createObject(channelArticle);
		}
	}
 
	public ChannelArticle getChannelArticle(Long articleId, Long channelId) {
		ChannelArticle ca = articleDao.getChannelArticle(articleId, channelId);
		if (ca == null) throw new BusinessException("未找到栏目文章关系！");
		
		return ca;
	}
	
    public PageInfo getChannelArticles(Long channelId, Integer pageNum, String...orderBy) {
       if( !channelDao.checkBrowsePermission(channelId) ) {
            log.error("用户【" + Environment.getOperatorName() + "】试图访问没有文章浏览权限的栏目【" + channelId + "】");
            return new PageInfo();
        }
        return articleDao.getPageList(channelId, pageNum, orderBy);
    }

	public Object[] searchArticleList(ArticleQueryCondition condition) {
		// 将用户有浏览权限的选定栏目下子栏目ID列表存入临时表中
		Long channelId = condition.getChannelId();
        List<Channel> children = channelDao.getChildrenById(channelId, CMSConstants.OPERATION_BROWSE);
		channelDao.insertEntityIds2TempTable(children);
		condition.setChannelId(null);
 
		PageInfo page = articleDao.getSearchArticlePageList(condition);
        List<?> list = page.getItems();
        
		List<Article> articleList = new ArrayList<Article>();
		if ( !EasyUtils.isNullOrEmpty(list) ) {
			for ( Object temp : list ) {
                Article article = ArticleHelper.createArticle((Object[]) temp);
				articleList.add(article);
			}
		}
		return new Object[]{articleList, page};
	}

    public boolean getArticleWorkflowPermission(String operationId, Long workFlowId) {
        return articleDao.checkArticleWorkflowPermission(operationId, workFlowId);
    }
}